package log

import (
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
)

// 包装了系统 log 的 Logger
type WrappedLogger struct {
	name  string
	level int // 日志水平

	prefix  func() string  // 前缀
	wrapped *WrappedLogger // 包装的 Logger

	file *os.File // 打开的文件
}

func NewWrappedLoggerWriter(w io.Writer) *WrappedLogger {
	log.SetOutput(w)
	return &WrappedLogger{level: LOG_LEVEL_DEBUG}
}

func NewWrappedLoggerFile(name, level string) (*WrappedLogger, error) {
	logger := &WrappedLogger{
		name:  name,
		level: FindLevel(level),
	}
	return logger, logger.open()
}

func (l *WrappedLogger) open() error {
	lg := l.logger()
	dir := filepath.Dir(lg.name)
	if err := os.MkdirAll(dir, 0755); err != nil {
		return err
	}
	file, err := os.OpenFile(lg.name, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
	if err != nil {
		return err
	}
	lg.file = file
	log.SetOutput(lg.file)
	return nil
}

func (l *WrappedLogger) Close() error {
	lg := l.logger()
	if lg.file != nil {
		return lg.file.Close()
	}
	return nil
}

func (l *WrappedLogger) WithPrefix(fn func() string) *WrappedLogger {
	return &WrappedLogger{prefix: fn, wrapped: l}
}

func (l *WrappedLogger) Debug(msg string, args ...any) {
	l.log(LOG_LEVEL_DEBUG, msg, args...)
}

func (l *WrappedLogger) Info(msg string, args ...any) {
	l.log(LOG_LEVEL_INFO, msg, args...)
}

func (l *WrappedLogger) Warn(msg string, args ...any) {
	l.log(LOG_LEVEL_WARN, msg, args...)
}

func (l *WrappedLogger) Error(msg string, args ...any) {
	l.log(LOG_LEVEL_ERROR, msg, args...)
}

func (l *WrappedLogger) log(level int, msg string, args ...any) error {
	lg := l.logger()
	if lg.level&level == 0 {
		return nil
	}
	if l.prefix == nil {
		l.print(logLevelMap[level], "", msg, args...)
	} else {
		l.print(logLevelMap[level], l.prefix(), msg, args...)
	}
	return nil
}

func (l *WrappedLogger) print(level, prefix, msg string, args ...any) {
	if prefix != "" {
		prefix = " " + prefix
	}
	if len(args) == 0 {
		log.Printf("[%s]%s %s", level, prefix, msg)
	} else {
		log.Printf("[%s]%s %s", level, prefix, fmt.Sprintf(msg, args...))
	}
}

func (l *WrappedLogger) logger() *WrappedLogger {
	if l.wrapped != nil {
		return l.wrapped
	}
	return l
}
